DEMO: Visualizing waves#

import numpy as np  
import matplotlib.pyplot as plt
from ipywidgets import interact, interactive
import scipy  
from scipy.constants import physical_constants, hbar, h, c, k, m_e, Rydberg, e, N_A

%matplotlib inline
%config InlineBackend.figure_format='retina'

Standing and traveling waves in 1D#

We begin by plotting a simple periodic function using numpy (np) and matplotlib.pyplot (plt)

\[y = \sin(kx)=\sin\left(\frac{2\pi}{\lambda} x\right)\]
L=0.3            # Try different wavelengths

x = np.linspace(0.0, 1.0, 1000)

y = np.sin(2 * np.pi * x/L)

plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x1666eec40>]
../_images/b0a77726734e88abe4226d4a391119896a44732031854a5399152909288d3d32.png

By putting above example inside a python function will make wavelength exploration convenient

def wave(L=2):
    
    x = np.linspace(0.0, 1.0, 1000)
    y = np.sin(2*np.pi * x/L)

    plt.plot(x, y, label=f'L={L}')
    
    plt.xlabel('x')
    plt.xlabel('y')
    plt.legend()
    plt.title('Sine waves')
    plt.show()
# Change wavelength
wave(L=0.5)
../_images/b99387a0b948b47823632e46c28074c27321ce4db6bb3aafc7ce321d70819c39.png

Interact with waves#

  • By adding @widgets.interact(parameters=(init,final)) to our functions we can interactively parameters in the function using slider widgets.

interactive(wave, L=(0.1, 2))

Traveling, standing waves and wave interference#

def wavef2(k=10, t=0, phi=0, v=1):

    x     = np.linspace(0, 1., 1000)
    
    wave1 = np.sin(k*(x-v*t)) 
    wave2 = np.sin(k*(x-v*t)+phi)    #try flipping the direction of velocity to get standing wave
    
    plt.plot(x, wave1,   lw=2, color='blue')
    plt.plot(x, wave2,   lw=2,  color='green')
    plt.plot(x, wave1+wave2, lw=3,  color='red')
    
    plt.ylim([-2.5, 2.5])
    plt.legend(['Wave1','Wave2','Wave1+Wave2'])
    plt.grid('on')
    plt.show()
interactive(wavef2, k=(2, 20), t=(0,50.0,0.1), phi=(0, 2*np.pi, np.pi/8),v=1)

Traveling wave as a function of time and position#

import plotly.express as px

def wave_x_t(A = 1, k = 1.0, omega = 1, phi = 0):
    
    # Create a grid of x and t values
    x = np.linspace(0, 2 * np.pi, 50)
    t = np.linspace(0, 2 * np.pi, 50)
    X, T = np.meshgrid(x, t)

    # Calculate the wave amplitude for each combination of x and t
    Y = A * np.sin(k * X - omega * T + phi)

    return px.scatter_3d(x=X.ravel(), 
              y=T.ravel(), 
              z=Y.ravel(), 
              color = Y.ravel(),
              labels={'x': 'Position', 'y': 'Time', 'z': 'Amplitude'},
              width=1000, 
              height=1000)
wave_x_t(A=1, k = 1.0, omega=2, phi=0)

Normal modes of 1D guitar string#

def wavef(n=1):
    
    L=1
    
    x = np.linspace(0, +1., 1000)
    
    y = np.sin(n*np.pi * x/L)
    
    plt.plot(x, y, lw=3)
    plt.title(label=f'Normal mode # {n}')
    plt.grid('--')
    plt.show()
interactive(wavef, n=(1,20))

1D guitar vibrations as linear combination of normal modes#

For simplicity we will combine two modes with two different mode numbers and shifted with resepct to each ophter by a phase \(\phi\).

\[Mode_1 = cos(\omega t) \cdot sin(n_1\pi \cdot \frac{x}{L})\]
\[Mode_2 = cos(\omega t+\phi) \cdot sin(n_2\pi \cdot \frac{x}{L})\]
def wavef(n1=1, n2=1, phi=0,t=0):
    
    L=1
    omega=1
     
    x = np.linspace(0, +1., 50)
    
    mode1 = np.cos(omega*t) * np.sin(n1*np.pi * x/L)
    
    mode2 = np.cos(omega*t + phi) * np.sin(n2*np.pi * x/L)
    
    plt.plot(x, mode1+mode2, lw=5, color='orange')
    plt.ylim([-2.5, 2.5])
    plt.grid('on')
    plt.show()
interactive(wavef, n1=(1,5), n2=(1,5), phi=(0,2*np.pi), t=(0,100,0.1) )

Normal modes of a 2D membrane#

def membrane2d(n=1, m=1): 
    
    # Constants
    Lx, Ly = 1.0, 1.0  # Dimensions of the rectangular region
    c = 1.0            # Wave speed
    
    # Create a spatial grid
    Nx, Ny = 100, 100
    x, y  = np.linspace(0, Lx, Nx), np.linspace(0, Ly, Ny)
    X, Y  = np.meshgrid(x, y)

    # Compute spatial part of the normal mode
    spatial_part = np.sin(m * np.pi * X / Lx) * np.sin(n * np.pi * Y / Ly)
   
    plt.contourf(X, Y, spatial_part, 40, cmap='RdBu')
    plt.show()
interactive(membrane2d, n=(1,10), m=(1,10))

Vibrations of square 2D membrane as a linear combination of normal modes#

import holoviews as hv
from holoviews import opts
hv.extension('plotly')

def wave_mode(n1, n2, m1=1, m2=1, t=1, omega=1, L = 1.0):
  '''Function to compute the 2D mode shapes'''
   
  x, y = np.linspace(0, L, 40), np.linspace(0, L, 40)
  X, Y = np.meshgrid(x, y)

  mode1 = np.cos(omega*t) * np.sin(n1*np.pi*X/L) * np.sin(m1*np.pi*Y/L) 
     
  mode2 = np.cos(omega*t) * np.sin(n2*np.pi*X/L) * np.sin(m2*np.pi*Y/L) 

  combined_mode = mode1+mode2

  return hv.Surface(combined_mode)

# Create a HoloMap containing the mode shapes
holomap = hv.HoloMap({(n1, n2, t): wave_mode(n1=n1, n2=n2, t=t) 
                      for n1 in range(1,5) 
                      for n2 in range(1,5)
                      for t in  range(0, 10)
                      }, 
                     kdims=['n1', 'n2', 't'])

holomap.opts(opts.Surface(cmap='jet', colorbar=True, width=900, height=900))